package middleware

import (
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"net/http"
	"seat-service/initialization"
	"seat-service/model"
	"seat-service/response"
	"seat-service/utils"
	"strconv"
	"strings"
)

func AuthMiddlewareCasbin(srv *utils.CasbinMethod) gin.HandlerFunc {
	// TODO  casbin校验
	// 1 获取当前用户的角色
	// 2 获取当前用户访问的 url  (get/post) 对应的菜单表信息  过滤掉一些公共接口
	// 3 通过casbin_rule表比较role是否有这个菜单表信息的id , 有代表有权限访问 ，无 代表无权限访问

	return func(context *gin.Context) {
		err := srv.Enforcer.LoadPolicy()
		if err != nil {
			zap.L().Error("srv.Enforcer.LoadPolicy() is failed", zap.Error(err))
			return
		}
		// 获取当前用户信息
		currentUser := getCurrentUser(context)

		// 查看当前登录的用户的角色是否被禁用
		var casbin model.CasbinRuleExtended
		if err := initialization.DB.Where("ptype = 'g' and v0 = ?", currentUser).Find(&casbin).Error; err != nil {
			initialization.SeatLogger.Error("Error querying user role", zap.Error(err))
			resp.Fail(context, response.CodeServerBusy, nil)
			context.AbortWithStatus(http.StatusInternalServerError)
			return
		}

		if casbin.Status == 0 {
			// 当前用户的角色被禁用
			resp.Fail(context, response.CodeRoleStop, nil)
			context.AbortWithStatus(http.StatusOK)
			return
		}

		// 获取请求的路径,方法
		requestPath := context.Request.URL.Path
		requestMethod := context.Request.Method

		// me 和 menu/routes 和数据看板接口不需要鉴权
		switch {
		case requestPath == "/app/user/me":
			context.Next()
			return
		case requestPath == "/app/menu/routes":
			context.Next()
			return
		case strings.Contains(requestPath, "app/data/"):
			context.Next()
			return
		case requestPath == "/app/qrCode/write/code":
			context.Next()
			return
		}

		// 根据请求路径和请求方法查询菜单id
		var menuInformation model.Menu
		condition := "(? LIKE CONCAT(request_url, '%%') OR request_url = ?) AND request_method LIKE ?"

		// 执行查询
		result := initialization.DB.
			Where(condition, requestPath, requestPath, "%"+requestMethod+"%").
			Find(&menuInformation)

		if result.Error != nil {
			initialization.SeatLogger.Error("Error querying menu information", zap.Error(result.Error))
			resp.Fail(context, response.CodeServerBusy, nil)
			context.AbortWithStatus(http.StatusInternalServerError)
			return
		}

		initialization.SeatLogger.Info("MENU ID", zap.Int("id", int(menuInformation.ID)))

		if menuInformation.ID == 0 {
			context.AbortWithStatus(http.StatusForbidden)
			return
		}
		//检查权限
		ok, err := srv.Enforcer.Enforce(currentUser, strconv.Itoa(int(menuInformation.ID)))
		if err != nil {
			initialization.SeatLogger.Error("srv.Enforcer.Enforce(currentUser, menuInformation.ID)", zap.Error(err))
			context.AbortWithStatus(403)
			return
		}

		if ok {
			//用户存在权限 , 继续请求处理
			context.Next()
		} else {
			//用户无权限 , 返回错误
			context.AbortWithStatus(403)
		}
	}
}

func getCurrentUser(context *gin.Context) string {
	userInformation, _ := context.Get(UserInformation)
	roleCode := userInformation.(utils.UserClaims).RoleCode
	//从会话或其它方式获取当前用户信息
	return strconv.Itoa(roleCode)
}
